import re
import os
import db
from decorators import cached_property
from errors import UserBaseError, ThirdLoginError
from utils.token import create_token, generate_reset_token, verify_reset_token
from settings import FRONT_URL
from utils.pwd import encrypt_pwd, validate_pwd
from utils.mail_send import SendEmail
from constants import HOME_PATH
from jinja2 import Environment, FileSystemLoader

REGISTER_CODE = "zsqljm"


def reset_pwd_send_mail(subject, toaddr, url):
    msg = SendEmail(subject, fromaddr="金风机器学习平台", toaddr=toaddr)
    base_path = os.path.join(HOME_PATH, "static")
    env = Environment(loader=FileSystemLoader(base_path))
    template = env.get_template("pwd_reset_temp.html")
    msg.add_html(template.render(template_url=url))
    msg.send()


class UserController(object):
    def __init__(self, id=None, username=None, email=None) -> None:
        self.id = id
        self.username = username
        self.email = email

    @cached_property
    def user(self):
        if self.id:
            return db.UsersTB.get(id=self.id)
        elif self.username:
            return db.UsersTB.get(username=self.username)
        elif self.email:
            return db.UsersTB.get(email=self.email)
        else:
            return None

    @cached_property
    def group(self):
        return db.UsersGroupTB.find_one(name=self.user["group_name"])

    @classmethod
    def email_rule_check(cls, email):
        if not re.match(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)", email):
            raise UserBaseError("邮箱格式错误")

    @classmethod
    def email_check(cls, email):
        user = None
        cls.email_rule_check(email)
        user = db.UsersTB.find_one(email=email)
        if user:
            raise UserBaseError("邮箱已注册")

    @classmethod
    def username_check(cls, username):
        user = db.UsersTB.find_one(username=username)
        if user:
            raise UserBaseError("用户已注册")

    @classmethod
    def register(cls, **kwargs):
        """
        注册
        """
        email = kwargs.get("email")
        username = kwargs.get("username")
        register_code = kwargs.pop("register_code")

        if email:
            cls.email_check(email)
        cls.username_check(username)

        if register_code != REGISTER_CODE:
            raise UserBaseError("未找到注册码")
        kwargs["group_name"] = "admin"
        kwargs["password"] = encrypt_pwd(kwargs.pop("password"))
        user_id = db.UsersTB.add(**kwargs)
        return UserController(id=user_id).user

    @classmethod
    def login(cls, **kwargs):
        """
        登录
        """
        user = UserController(username=kwargs["username"]).user
        if not user or not validate_pwd(user["password"], kwargs["password"]):
            raise UserBaseError("用户名或密码错误")
        token = create_token({"name": user["username"]})
        return token

    @classmethod
    def third_login(cls, **kwargs):
        """
        三方登录
        """
        code = kwargs["code"]
        project = kwargs["project"]

        # 动态处理查询
        try:
            if project == "xihe":
                res = db.UsersCodeTB.find_one(xihe=code)
        except Exception:
            raise ThirdLoginError

        token = None
        if res:
            user_id = res[0]
            user = db.UsersTB.get(id=user_id)
            token = create_token({"name": user["username"]})

        return token

    @classmethod
    def retrieve_password(cls, **kwargs):
        """
        找回密码
        """
        username = kwargs.get("username")
        email = kwargs.get("email")
        try:
            user = db.UsersTB.get(email=email)
            if user["username"] != username:
                raise UserBaseError("用户名和邮箱不匹配")
        except UserBaseError:
            user = db.UsersTB.get(username=username)
            if user["email"] != email:
                raise UserBaseError("用户名和邮箱不匹配")

        # 生成表示并发送邮件
        token = generate_reset_token(username)
        url = FRONT_URL + "/resetPassword/" + token
        reset_pwd_send_mail("重置密码", [email], url)

    @classmethod
    def reset_password(cls, **kwargs):
        """
        重置密码
        """
        token = kwargs.pop("token")
        password = kwargs.pop("password")

        username = verify_reset_token(token)
        kwargs["password"] = encrypt_pwd(password)
        db.UsersTB.set(password=kwargs["password"]).where(username=username)
        return UserController(username=username).user

    def edit_password(self, **kwargs):
        """
        修改密码
        """
        password = kwargs.pop("password")

        user = self.user
        kwargs["password"] = encrypt_pwd(password)
        db.UsersTB.set(password=kwargs["password"])
        return user

